package cn.zhxu.pack;

import com.jfinal.template.Engine;
import com.jfinal.template.Template;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class Packer {

    private final String configName;
    private final Map<String, Object> data;

    private int inputBasePathLength;
    private final String outputBasePath;

    private final Map<String, Object> trackData;

    private static final Engine engine;

    static {
        engine = Engine.create("e-pack");
        Engine.addExtensionMethod(String.class, ColorStrExt.class);
    }


    public Packer(String configName, String outputBasePath, Properties properties, Map<String, Object> trackData) {
        this.configName = configName;
        this.outputBasePath = outputBasePath;
        this.data = toData(properties);
        this.trackData = trackData;
    }

    private Map<String, Object> toData(Properties properties) {
        Map<String, Object> data = new HashMap<>();
        for (String name: properties.stringPropertyNames()) {
            String value = properties.getProperty(name);
            putIntoMap(data, name.trim(), value);
        }
        return data;
    }


    private void putIntoMap(Map<String, Object> data, String name, String value) {
        String[] keys = name.split("\\.");
        for (int i = 0; i < keys.length; i++) {
            String key = keys[i];
            if (i == keys.length - 1) {
                if (data.containsKey(key)) {
                    System.err.println("conflict config key in [" + configName + "]: " + name);
                    System.exit(1);
                }
                data.put(key, value != null ? value.trim() : null);
                break;
            }
            Object object = data.computeIfAbsent(key, k -> new HashMap<String, Object>());
            if (object instanceof Map) {
                //noinspection unchecked
                data = (Map<String, Object>) object;
            } else {
                System.err.println("conflict config key in [" + configName + "]: " + name);
                System.exit(1);
            }
        }
    }

    /**
     *
     * @param inputFile
     * @return 编译文件个数
     */
    public int doPack(File inputFile) throws IOException {
        if (inputBasePathLength == 0) {
            inputBasePathLength = inputFile.getPath().length();
        }
        int fcount = 0;
        if (inputFile.isDirectory()) {
            File[] files = inputFile.listFiles();
            if (files == null) {
                return fcount;
            }
            for (File file : files) {
                fcount += doPack(file);
            }
        } else if (inputFile.isFile()) {
            String inputFileName = inputFile.getPath();
            String relativeInputPath = inputFileName.substring(inputBasePathLength);
            if (trackData != null) {
                Long lastModified = (Long) trackData.get(relativeInputPath);
                if (lastModified != null && inputFile.lastModified() <= lastModified) {
                    // 该文件未被修改过
                    return fcount;
                }
            }
            if (Utils.isTxtFile(inputFile) && !shouldIgnore(relativeInputPath)) {
                packFile(inputFileName, relativeInputPath);
            } else {
                copyFile(inputFile, relativeInputPath);
            }
            if (trackData != null) {
                trackData.put(relativeInputPath, System.currentTimeMillis());
            }
            fcount++;
        }
        return fcount;
    }

    private boolean shouldIgnore(String relativeInputPath) {
        String[] ignores = Config.me().getIgnores();
        if (ignores == null) {
            return false;
        }
        for (String ignore : ignores) {
            if (relativeInputPath.startsWith(ignore)) {
                return true;
            }
        }
        return false;
    }

    private void packFile(String inputFileName, String relativeInputPath) {
        String outputPath = outputBasePath + "\\" + configName + relativeInputPath;
        Template template = engine.getTemplate(inputFileName);
        template.render(data, Utils.writeableFile(outputPath));
        System.out.println("\t" + relativeInputPath);
    }

    private void copyFile(File file, String relativeInputPath) throws IOException {
        String outputPath = outputBasePath + "\\" + configName + relativeInputPath;
        Files.copy(file.toPath(), Utils.writeableFile(outputPath).toPath());
    }

    public static void main(String[] args) {
        Template template = engine.getTemplate("C:/Users/troy/Desktop/gradient.d.ts");
        template.render(new HashMap<>(), Utils.writeableFile("C:/Users/troy/Desktop/gradient.out.d.ts"));
    }

}
